from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.routing import APIRoute

from config.settings import Settings
from schemas.userInfo import UserInfo
from utils.authManager import TokenManager
from utils.businessException import BusinessException

class AuthMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        super().__init__(app)
    async def dispatch(self, request: Request, call_next):
        if request.method == "OPTIONS":return await call_next(request)
        path = request.url.path

        # dev 环境跳过权限验证
        settings = Settings()
        if settings.ENV == "dev":
            request.state.user = UserInfo(
                    id=1,
                    user_role='xx',
                    user_name='admin'
                )
            return await call_next(request)

        # 排除非api请求
        root_path = request.scope.get('root_path')
        if not path.startswith(root_path):return await call_next(request)
        if path in ["/docs", f"{root_path}/openapi.json"]:return await call_next(request)

        # 检查是否跳过权限验证
        route = next(route for route in request.app.routes if isinstance(route, APIRoute) 
                     and route.matches(request.scope)[0]
                     and request.scope.get('root_path')+route.path==path)
        if getattr(route.endpoint, 'skip_auth', False):return await call_next(request)

        # check token
        token = request.headers.get("Authorization") or ''
        token = token.lstrip('Bearer ')
        if not token:raise BusinessException(status_code=401,code=401, msg="Unauthorized")
        
        token_payload = TokenManager().verify_token(token)
        if not token_payload:
            raise Exception("Invalid token")
        request.state.user = UserInfo(
                id=token_payload.get("user_id"),
                user_role=token_payload.get("user_role"),
                user_name=token_payload.get("user_name")
            )     
        
        return await call_next(request)